import {clsx, type ClassValue} from 'clsx';
import {twMerge} from 'tailwind-merge';
import {getExtensionId} from '@/lib/extensionEnv';

// CSS类名合并工具函数
// 结合clsx和tailwind-merge，智能合并和去重CSS类名
export function cn(...inputs: ClassValue[]) {
    return twMerge(clsx(inputs));
}

// 防抖函数
// 用于延迟执行函数，避免频繁调用
// 带取消与立即触发能力的防抖函数（向后兼容：仍可当作普通函数调用）
export type Debounced<T extends (...args: any[]) => any> = ((...args: Parameters<T>) => void) & {
    cancel: () => void;
    flush: () => void;
};

export function debounce<T extends (...args: any[]) => any>(
    func: T,
    wait: number
): Debounced<T> {
    let timeout: ReturnType<typeof setTimeout> | null = null;
    let lastArgs: Parameters<T> | null = null;

    function invoke(this: any) {
        timeout = null;
        const invokeArgs = lastArgs as Parameters<T>;
        lastArgs = null;
        func.apply(this, invokeArgs);
    }

    const debounced = function (this: any, ...args: Parameters<T>) {
        lastArgs = args;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => invoke.call(this), wait);
    } as Debounced<T>;

    debounced.cancel = () => {
        if (timeout) {
            clearTimeout(timeout);
            timeout = null;
        }
        lastArgs = null;
    };

    debounced.flush = function (this: any) {
        if (timeout) {
            clearTimeout(timeout);
            invoke.call(this);
        }
    };

    return debounced;
}

// 格式化日期
export function formatDate(timestamp: number, format: 'relative' | 'absolute' = 'relative'): string {
    const date = new Date(timestamp);
    const now = Date.now();
    const diff = now - timestamp;

    if (format === 'absolute') {
        return date.toLocaleString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
        });
    }

    // 相对时间格式
    const minute = 60 * 1000;
    const hour = minute * 60;
    const day = hour * 24;
    const month = day * 30;

    if (diff < minute) {
        return '刚刚';
    } else if (diff < hour) {
        return `${Math.floor(diff / minute)}分钟前`;
    } else if (diff < day) {
        return `${Math.floor(diff / hour)}小时前`;
    } else if (diff < month) {
        return `${Math.floor(diff / day)}天前`;
    } else {
        return date.toLocaleDateString('zh-CN');
    }
}

// 格式化集合时间显示
export function formatCollectionTime(createdAt: number, updatedAt: number): {
    text: string;
    tooltip: string;
} {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const todayTimestamp = today.getTime();

    // 如果更新时间在今天，显示更新时间
    if (updatedAt >= todayTimestamp) {
        const relativeTime = formatDate(updatedAt);
        return {
            text: `${relativeTime}更新`,
            tooltip: formatDate(updatedAt, 'absolute')
        };
    }

    // 否则显示创建时间
    const absoluteTime = formatDate(createdAt, 'absolute');
    return {
        text: `创建于 ${absoluteTime}`,
        tooltip: absoluteTime
    };
}

// 从URL提取域名
export function extractDomain(url: string): string {
    try {
        return new URL(url).hostname;
    } catch {
        return url;
    }
}

// 深度克隆对象（简化版）
export function deepClone<T>(obj: T): T {
    if (obj === null || typeof obj !== 'object') return obj;
    if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T;
    if (obj instanceof Array) return obj.map(item => deepClone(item)) as unknown as T;
    if (typeof obj === 'object') {
        const cloned = {} as { [key: string]: any };
        Object.keys(obj).forEach(key => {
            cloned[key] = deepClone((obj as { [key: string]: any })[key]);
        });
        return cloned as T;
    }
    return obj;
}

// 生成唯一标识符（支持可选前缀参数）
// 向后兼容：无参数时使用简化格式，有前缀时使用语义化格式
export function generateId(prefix?: string): string {
    // 时间戳转36进制（紧凑格式）
    const timestamp = Date.now().toString(36);
    // 随机数转36进制并截取
    const random = Math.random().toString(36).slice(2, 11);
    // 根据是否有前缀返回不同格式
    return prefix ? `${prefix}_${timestamp}_${random}` : `${timestamp}_${random}`;
}

// ---------------- 文本长度与校验常量（集中管理） ----------------
export const TITLE_MAX_EFFECTIVE = 60;   // 标题最大等效长度（中文=2，英文=1）// 备注最大等效长度// 备注软提醒阈值（不阻塞保存）
export const URL_MAX_LENGTH = 65530;     // URL 最大原始字符长度（无软提醒）
export const COLLECTION_MAX_EFFECTIVE = 70; // 集合名称最大等效长度

// 通用：按“中文=2，英文=1”计算等效长度（供各处复用）
export function getEffectiveTextLength(input: string): number {
    const trimmed = (input ?? '').trim();
    let len = 0;
    for (const char of trimmed) {
        // 使用Unicode编码范围判断是否为中文字符（含常用汉字、扩展区、全角标点）
        if (/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(char)) {
            len += 2;
        } else {
            len += 1;
        }
    }
    return len;
}

// 验证空间名称长度（支持中英文混合计算）
// 中文字符算作2个字符，英文字符算作1个字符
// 限制：最多15个中文字符或30个英文字符的等价长度
export function validateSpaceName(name: string): { isValid: boolean; message?: string } {
    // 去除首尾空格
    const trimmedName = name.trim();

    // 检查是否为空
    if (!trimmedName) {
        return { isValid: false, message: '空间名称不能为空' };
    }

    // 使用通用等效长度计算函数
    const effectiveLength = getEffectiveTextLength(trimmedName);

    // 检查长度限制（等效30个英文字符）
    if (effectiveLength > 30) {
        return {
            isValid: false,
            message: '空间名过长'
        };
    }

    return { isValid: true };
}

// 便捷：返回空间名错误消息（有效时为 undefined）
export function getSpaceNameError(name: string): string | undefined {
    const { isValid, message } = validateSpaceName(name);
    return isValid ? undefined : message;
}

// 验证集合名称（中文=2，英文=1；≤ 70 等效字符，且非空）
export function validateCollectionName(name: string): { isValid: boolean; message?: string } {
    const trimmed = (name ?? '').trim();
    if (!trimmed) return { isValid: false, message: '集合名称不能为空' };
    const len = getEffectiveTextLength(trimmed);
    if (len > COLLECTION_MAX_EFFECTIVE) return { isValid: false, message: '集合名称过长' };
    return { isValid: true };
}

export function getCollectionNameError(name: string): string | undefined {
    const { isValid, message } = validateCollectionName(name);
    return isValid ? undefined : message;
}

// 判断 URL 是否为系统/扩展页面
// 检测多种浏览器的内部协议和扩展页面
export function isSystemOrExtensionUrl(url: string): boolean {
    // 统一转为小写进行比较
    const u = url.toLowerCase();
    // 多种浏览器的内部协议
    return (
        u.startsWith('chrome://') ||
        u.startsWith('edge://') ||
        u.startsWith('brave://') ||
        u.startsWith('vivaldi://') ||
        u.startsWith('opera://') ||
        u.startsWith('about:') ||
        u.startsWith('chrome-extension://')
    );
}

/**
 * 检查标签页是否为当前扩展的起始页面
 * @param tab - 标签页信息，包含URL和标题
 * @returns 是否为当前扩展的起始页面
 */
export function isExtensionStartPage(tab: { url?: string; title?: string }): boolean {
    const { url, title } = tab;
    if (!url) return false;

    try {
        // 系统新标签页：需要URL和标题都匹配
        if (url === 'chrome://newtab/' || url === 'chrome://newtab') {
            const extensionName = chrome.runtime.getManifest().name;
            return title === extensionName;
        }

        // 扩展覆盖的新标签页：只需URL匹配
        const u = new URL(url);
        if (u.protocol === 'chrome-extension:') {
            const runtimeId = getExtensionId();
            return !!(runtimeId && u.host === runtimeId && u.pathname === '/dashboard.html');
        }
    } catch {
        // 非法URL或无法解析，视为非起始页
    }
    return false;
}

// 生成默认favicon占位符SVG
// 返回Base64编码的灰色占位符图标，避免图标加载失败时的空白显示
export function getDefaultFaviconSvg(): string {
    return "data:image/svg+xml;charset=utf-8," +
        encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64">
<rect width="64" height="64" fill="#f2f2f2"/>
<circle cx="32" cy="32" r="12" fill="#c9c9c9"/>
</svg>`);
}

export function calculateDragPositionUpdates<T extends { id: number; position: number }>(
    sortedItems: T[],
    targetIndex: number
): Array<{ id: number; position: number }> {
    const movedItem = sortedItems[targetIndex];
    const updates: Array<{ id: number; position: number }> = [];

    const prevPosition = targetIndex === 0 ? null : sortedItems[targetIndex - 1].position;
    const nextPosition = targetIndex === sortedItems.length - 1 ? null : sortedItems[targetIndex + 1].position;

    if (prevPosition === null) {
        updates.push({
            id: movedItem.id,
            position: nextPosition! - 1000
        });
    } else if (nextPosition === null) {
        updates.push({
            id: movedItem.id,
            position: prevPosition + 1000
        });
    } else {
        const gap = nextPosition - prevPosition;

        if (gap >= 2) {
            updates.push({
                id: movedItem.id,
                position: Math.floor((prevPosition + nextPosition) / 2)
            });
        } else {
            const itemsToReorder = [movedItem];
            let endIndex = targetIndex + 1;

            while (endIndex < sortedItems.length) {
                itemsToReorder.push(sortedItems[endIndex]);
                endIndex++;

                if (endIndex < sortedItems.length) {
                    const nextGap = sortedItems[endIndex].position - prevPosition;
                    if (nextGap >= (itemsToReorder.length + 1) * 2) {
                        break;
                    }
                } else {
                    break;
                }
            }

            const totalGap = (endIndex < sortedItems.length ? sortedItems[endIndex].position : prevPosition + itemsToReorder.length * 1000) - prevPosition;
            const step = Math.floor(totalGap / (itemsToReorder.length + 1));

            for (let i = 0; i < itemsToReorder.length; i++) {
                updates.push({
                    id: itemsToReorder[i].id,
                    position: prevPosition + (i + 1) * step
                });
            }
        }
    }

    return updates;
}

// 复制文本到剪贴板（优先现代API；必要时启用降级回退以"尽可能成功"）
export async function copyToClipboard(text: string): Promise<boolean> {
    // 尝试路径：
    // 1) navigator.clipboard.writeText（安全上下文/扩展页 + 用户手势）
    // 2) 回退：隐藏 <textarea> + document.execCommand('copy')（兼容旧环境/HTTP）

    // --------- 环境快速校验 ---------
    // 无浏览器环境（SSR/Node）直接失败
    if (typeof window === 'undefined' || typeof document === 'undefined') {
        return false;
    }

    // --------- 首选：异步剪贴板API ---------
    try {
        // 检查是否支持 navigator.clipboard
        if (typeof navigator !== 'undefined' && 'clipboard' in navigator && navigator.clipboard) {
            // 尝试聚焦窗口，减少 NotAllowedError 发生概率
            try {
                // 某些浏览器要求页面可聚焦（无副作用）
                window.focus?.();
            } catch {}

            // 写入文本
            await navigator.clipboard.writeText(text);
            return true;
        }
    } catch (err: any) {
        // 如果是权限/无手势导致的拒绝，降级到回退方案
        // 继续向下执行，不直接 return false
        if (process.env.NODE_ENV !== 'production') {
            console.warn('[copyToClipboard] Async API failed, fallback to execCommand:', err);
        }
    }

    // --------- 回退方案：隐藏 textarea + execCommand ---------
    try {
        // 创建隐藏的 textarea
        const textArea = document.createElement('textarea');
        // 避免在 iOS 上缩放
        textArea.style.fontSize = '12pt';
        // 脱离视窗且可被选择
        textArea.style.position = 'fixed';
        textArea.style.top = '0';
        textArea.style.left = '-9999px';
        textArea.style.opacity = '0';
        // 设为只读以防移动端弹出软键盘
        textArea.setAttribute('readonly', '');
        // 设置待复制文本
        textArea.value = text;
        // 添加到 DOM
        document.body.appendChild(textArea);

        // 选中文本（兼容 iOS）
        textArea.select();
        textArea.setSelectionRange(0, textArea.value.length);

        // 执行复制命令（虽标记为废弃，但仍是最广泛可用的降级路径）
        const ok = document.execCommand && document.execCommand('copy');

        // 清理 DOM
        document.body.removeChild(textArea);

        if (ok) return true;
    } catch (err) {
        // 回退方案也失败
        console.error('[copyToClipboard] Fallback copy failed:', err);
    }

    // --------- 最终失败 ---------
    return false;
}
